package org.jfunction.parser;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;

import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.ITypedRegion;
import org.eclipse.jface.text.rules.FastPartitioner;
import org.jfunction.JFunctionFile;
import org.jfunction.internal.parser.DefaultProblemHandler;
import org.jfunction.internal.parser.ExamplesParser;
import org.jfunction.internal.parser.JFunctionPartitionScanner;
import org.jfunction.internal.parser.KeyWords;
import org.jfunction.internal.parser.ScenarioParser;

public class JFunctionFileParser {
	private final ScenarioParser scenarioDefinitionParser;
	private final ExamplesParser examplesSectionParser;
	private final Document document;
	private JFunctionFile jfFile;
	private ProblemHandler collector;
	
	public JFunctionFileParser() {
		KeyWords keywords = new KeyWords();
		this.scenarioDefinitionParser = new ScenarioParser(keywords);
		this.examplesSectionParser = new ExamplesParser(keywords);
		JFunctionPartitionScanner scanner = new JFunctionPartitionScanner(keywords);
		IDocumentPartitioner partitioner = new FastPartitioner(scanner,
				new String[] {JFunctionPartitionScanner.SCENARIO,JFunctionPartitionScanner.EXAMPLES });
		this.document = new Document();
		partitioner.connect(document);
		document.setDocumentPartitioner(partitioner);
	}
	
	public void setParseProblemCollector(ProblemHandler collector) {
		this.collector = collector;
	}

	public synchronized JFunctionFile parseFile(File file) throws ParseException {
		try {
			FileReader reader = new FileReader(file);
			char[] chars = new char[1024];
			int len = 0;
			StringBuilder sb = new StringBuilder();
			while((len = reader.read(chars)) != -1) {
				sb.append(chars,0,len);
			}
			String text = sb.toString();
			return parseText(text);
		} catch (FileNotFoundException e) {
			throw new ParseException(e);
		} catch (IOException e) {
			throw new ParseException(e);
		}
	}

	public synchronized JFunctionFile parseText(String text) throws ParseException {
		document.set(text);
		jfFile = new JFunctionFile(text);
		if (this.collector == null) {
			this.collector = new DefaultProblemHandler();
		}
		try {
			ITypedRegion[] regions = document.computePartitioning(0,document.getLength());
			if (regions.length > 0) {
				ITypedRegion scenarioRegion = regions[0];
				if (JFunctionPartitionScanner.SCENARIO.equals(scenarioRegion.getType())) {
					scenarioDefinitionParser.parse(document, scenarioRegion,jfFile);
				} else {
					collector.add(new Problem(-1,ProblemType.NO_SCENARIO));
				}
				if (regions.length > 1) {
					ITypedRegion examplesRegion = regions[1];
					if (JFunctionPartitionScanner.EXAMPLES.equals(examplesRegion.getType())) {
						examplesSectionParser.parse(document, examplesRegion,jfFile);
					} else {
						collector.add(new Problem(document.getLineOffset(examplesRegion.getOffset()),ProblemType.ONLY_EXAMPLES_HERE));
					}
				}
			} else {
				collector.add(new Problem(-1,ProblemType.UNPARSEABLE));
			}
		} catch (BadLocationException e) {
			throw new ParseException(e);
		} finally {
			this.collector = null;
			document.set("");
		}
		return jfFile;
	}
}
